GLOBAL  _read_msw,_lidt
GLOBAL  _int_08_hand
GLOBAL  _int_09_hand
GLOBAL  _int_0E_hand
GLOBAL  _int_7F_hand
GLOBAL	_int_80_hand
GLOBAL	_int_74_hand
GLOBAL	_sys_yield
GLOBAL 	_syscall
GLOBAL	_inport
GLOBAL	_outport
GLOBAL  _mascaraPIC1, _mascaraPIC2, _Cli, _Sti, _halt
GLOBAL  _debug
GLOBAL  _read_cr0
GLOBAL  _write_cr0
GLOBAL  _read_cr3
GLOBAL  _write_cr3

EXTERN	schedule
EXTERN	switchToSchedulingContext
EXTERN	updateSleepingProcesses
EXTERN  int_08
EXTERN  int_09
EXTERN  int_74
EXTERN  int_80
EXTERN	pageFault


SECTION .text


_Cli:
	cli			; limpia flag de interrupciones
	ret

_Sti:

	sti			; habilita interrupciones por flag
	ret

_halt:
	hlt
	ret

; Escribe mascara del PIC 1
_mascaraPIC1:
	push    ebp				;Armo el stackframe
	mov     ebp, esp
	mov     ax, [ss:ebp+8]	; ax = mascara de 16 bits
	out	21h,al
	pop     ebp
	retn

; Escribe mascara del PIC 2
_mascaraPIC2:
	push    ebp				;Armo el stackframe
	mov     ebp, esp
	mov     ax, [ss:ebp+8]	; ax = mascara de 16 bits
	out	0A1h,al
	pop     ebp
	retn

_read_msw:
	smsw    ax			; Obtiene la Machine Status Word
	retn

; Carga el IDTR
_lidt:
	push    ebp					;Armo el stackframe
	mov     ebp, esp
	push    ebx
	mov     ebx, [ss: ebp + 6] 	; ds:bx = puntero a IDTR
	rol	ebx,16
	lidt    [ds: ebx]          	; carga IDTR
	pop     ebx
	pop     ebp
	retn


_read_cr0:
	mov eax, cr0
	retn

_write_cr0:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov cr0,  eax
	pop ebp
	retn

_read_cr3:
	mov eax, cr3
	retn

_write_cr3:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov cr3, eax
	pop ebp
	retn


; Handler de INT 8 ( Timer tick)
_int_08_hand:
	cli

	pushad

	push esp						;salvo el stack del proceso anterior
	call switchToSchedulingContext	;cambio el stack por el de scheduling
	mov esp, eax					;seteo el stack de scheduling
	call updateSleepingProcesses	;actualizo a los procesos que duermen

	mov eax, 0						;le digo al scheduler que no lo llame con yield
	push eax
	call schedule					;elige el nuevo proceso, devuelve su stack
	mov esp,eax						;cambio el stack por el del nuevo proceso

	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al

	popad

	iret

; Handler de INT 7F (llamada por yield)
; es como la INT 08, pero no actualiza el sleep
_int_7F_hand:
	cli

	pushad

	push esp						;salvo el stack del proceso anterior
	call switchToSchedulingContext	;cambio el stack por el de scheduling
	mov esp, eax					;seteo el stack de scheduling

	mov eax, 1						;le digo al scheduler que lo llame con yield
	push eax
	call schedule					;elige el nuevo proceso, devuelve su stack
	mov esp,eax						;cambio el stack por el del nuevo proceso

	popad

	iret

; Handler de INT 9 ( Teclado)
_int_09_hand:
	push    ds
	push    es
	pusha				; Se salvan los registros

	mov	dx, 60h			; se busca del puerto 60h el scancode de
	in	al, dx			; la tecla presionada
	push eax			; se pushea el scancode para la funcion int_09

	mov     ax, 10h		; Carga de DS y ES con el valor del selector
	mov     ds, ax		; a utilizar.
	mov     es, ax

	call    int_09		;funcion de c que usa el scancode

	pop	eax

	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al

	popa
	pop     es
	pop     ds
	iret


; Handler de la excepcion Page Fault
_int_0E_hand:
	push    ds
	push    es
	pusha				; Se salvan los registros

	mov     ax, 10h		; Carga de DS y ES con el valor del selector
	mov     ds, ax		; a utilizar.
	mov     es, ax

	call    pageFault

	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al

	popa
	pop     es
	pop     ds
	iret


; Handler de INT 74 (Mouse)
_int_74_hand:
	push    ds
	push    es
	pusha				; Se salvan los registros

	mov	dx, 60h			; se busca del puerto 60h el codigo que
	in	al, dx			; envia el mouse
	push eax			; se pushea el scancode para la funcion int_74

	mov     ax, 10h		; Carga de DS y ES con el valor del selector
	mov     ds, ax		; a utilizar.
	mov     es, ax

	call    int_74

	pop	eax

	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	out	0A0h,al			; Envio de EOI generico al PIC2

	popa
	pop     es
	pop     ds
	iret

; Handler de INT 80 (syscall)
_int_80_hand:
	cli

	push	edi			;argumento 5 (char*)
	push	esi			;argumento 4 (char*)
	push 	edx			;argumento 3 (int)
	push 	ecx			;argumento 2 (int)
	push 	ebx			;argumento 1 (int)
	push	eax			;numero de operacion (int)

	call	int_80

	add		esp, 24

	sti
	iret

;funcion encargada de llamar a la INT 80h
_syscall:
	push ebp
	mov ebp, esp

	push	ebx			;Salvo los registros que voy a usar
	push	ecx
	push	edx
	push	esi
	push	edi

	mov eax, [ebp + 8]	;numero de operacion (int)
	mov ebx, [ebp + 12]	;argumento 1 (int)
	mov ecx, [ebp + 16]	;argumento 2 (int)
	mov edx, [ebp + 20]	;argumento 3 (int)
	mov esi, [ebp + 24]	;argumento 4 (char*)
	mov edi, [ebp + 28]	;argumento 5 (char*)

	int 80h				;llamo a la INT 80h, en eax me queda la respuesta

	pop		edi
	pop		esi
	pop		edx
	pop		ecx
	pop		ebx

	pop ebp
	ret

_sys_yield:
	push    ebp			;Armo el stackframe
	mov     ebp, esp

	int 	7Fh

	pop     ebp
	ret

;realiza in de un puerto indicado, y deja en al la respuesta
_inport:
	push    ebp			;Armo el stackframe
	mov     ebp, esp

	push	edx

	mov		eax, [ss: ebp + 8]	;el nro de puerto
	mov		dx, ax

	mov 	eax, 0h
	in		al, dx		;en al dejo la respuesta del puerto

	pop		edx

	pop     ebp
	ret

;realiza out de un dato a un puerto indicado
_outport:
	push    ebp			;Armo el stackframe
	mov     ebp, esp

	push	edx

	mov		edx, [ss: ebp + 8]	;el nro de puerto

	mov		eax, [ss: ebp + 12]	;el dato

	out		dx, al

	pop		edx

	pop     ebp
	ret


; Debug para el BOCHS, detiene la ejecucion;
; Para continuar colocar en el BOCHSDBG: set $eax=0
_debug:
        push    bp
        mov     bp, sp
        push	ax
vuelve:	mov     ax, 1
        cmp	ax, 0
		jne	vuelve
		pop	ax
		pop     bp
        retn
